# -*- coding: utf-8 -*-
# @Time : 2023/8/25 13:44
# @Author : cute
# @Email : Aggressive_cute@126.com
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from loguru import logger
import base64
import requests
import secrets
import json
import random
import string
import time

headers = {
    "Accept": "*/*",
    "Accept-Language": "zh-CN,zh;q=0.9",
    "Cache-Control": "no-cache",
    "Connection": "keep-alive",
    "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
    "Origin": "https://gitee.com",
    "Pragma": "no-cache",
    "Referer": "https://gitee.com/login",
    "Sec-Fetch-Dest": "empty",
    "Sec-Fetch-Mode": "cors",
    "Sec-Fetch-Site": "same-origin",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
    "X-CSRF-Token": "b+Cbfwy0nbgTg8dyu8Q9SMQsF3ptcGL3TuGyRFGI3vrRoRPVS6o/Ul50gzfNktVonM7rktg7VcGmkNoCri7Aug==",
    "X-Requested-With": "XMLHttpRequest",
    "sec-ch-ua": "\"Google Chrome\";v=\"125\", \"Chromium\";v=\"125\", \"Not.A/Brand\";v=\"24\"",
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": "\"Windows\""
}
cookies = {
    "user_locale": "zh-CN",
    "oschina_new_user": "false",
    "user_return_to_0": "%2Fq",
    "gitee-session-n": "am41bys0alZFVUZrMUF3MFdsQUpYK01Ba1FzM3VrQWcwREsyWGRjWk42cU5DcFpBd0hZaSs3QVQzQU9BTmZsUHdOMlZ4NkoxSEFRRG1FNzJIWEVjUkpubjcyaTIrb0ZZL3BmMHQrRHdhUEJ0Rmk0SHY1N01ZV2cvRkphN2NpVlNsOEtnNHJQSmJxR1ZkMU9Ja3dXcEtnNS9rOVJHaFBxWVBjTGZ4aVF3TmFUUXVsMTdJeDkzcVVUTGhUU0tUWFRrNVB5Q1JObXlNa084SSs2bHROKzdIRjQwRlpDcWtyOGlRc1ZKeWJYbmhnK0RNTjRYc1JjalJRbFl0bDJPMXRsL1Q2Qk1RUGV0Qkd5TDBDaWVmWnVLT09EeHJXRnlGdU13ZWhDemNKd0tja0EvOWduOXRocUptMUxPdCtjaFI2NHR0d3dqcWowU0hEWUR6WkgzUHFjU1pyUUxvTlovWnVRNzUxWm5rUXlGSVVGU1YwNGhBWXNUVHlQeUpOQ3oyeHdRTXJObTVzdWxNdjZIcVhEcFUydk12SnNmSTl3TDB0eWQ0ZnMyMFVJNFoyVzQ3K1Uzc1NnRDZaT0RJc29pM3pZWC0tTDZidWlaQXJ4bklPY3RqcUovZXRCUT09--378cd705a09200dada198d7b2d65488d62344ef1",
    "tz": "Asia%2FShanghai",
    "sensorsdata2015jssdkcross": "%7B%22distinct_id%22%3A%22190632d5591ad1-074c9fd9cb0b4ec-26001c51-2073600-190632d559211e6%22%2C%22first_id%22%3A%22%22%2C%22props%22%3A%7B%7D%2C%22%24device_id%22%3A%22190632d5591ad1-074c9fd9cb0b4ec-26001c51-2073600-190632d559211e6%22%7D",
    "sajssdk_2015_cross_new_user": "1",
    "Hm_lvt_24f17767262929947cc3631f99bfd274": "1719650839",
    "Hm_lpvt_24f17767262929947cc3631f99bfd274": "1719650839",
    "yp_riddler_id": "55551ce6-7b80-4a17-8fdd-8ac689f442cc"
}


def dumps(data_dict):
    """
    字典数据序列化
    :return:
    """
    return json.dumps(data_dict, separators=(',', ':'), ensure_ascii=False)


def my_rsa(publick_key: str, data: str):
    """
    rsa加密
    :return:
    """
    pub_key = RSA.importKey(base64.b64decode(publick_key))
    rsa = PKCS1_v1_5.new(pub_key)
    result = base64.b64encode(rsa.encrypt(data.encode("utf-8"))).decode()
    return result


def ocr_slide_distance(target_bytes, background_bytes):
    """
    云片滑块 计算滑块距离
    统一距离缩放
    :return:
    """
    import ddddocr
    slide = ddddocr.DdddOcr(det=False, ocr=False, show_ad=False)
    res = slide.slide_match(target_bytes, background_bytes, simple_target=True)
    return int(res["target"][0] / 1.45)


def random_cb():
    def generate_random_key(length=10):
        # 使用secrets库生成一个安全的随机字符串作为键
        return ''.join(secrets.choice(string.ascii_lowercase + string.digits) for i in range(length))

    pool = {
        "c0p8cnatq6": {"ts": None},
        "3250um6lp2o": {"ts": None},
    }
    while True:
        key = generate_random_key()
        if key not in pool:
            break
    pool[key] = {"ts": float('inf')}

    return key


class CloudSheet():

    def __init__(self,captcha_id,fp,yp_riddler_id):
        self.key = self.generate_random_string(16)
        self.iv = self.generate_random_string(16)

        self.fp = fp
        self.captchaId = captcha_id
        self.yp_riddler_id = yp_riddler_id

        self.session = requests.session()
        self.session.headers.update(headers)
        self.session.cookies.update(cookies)

    def generate_random_string(self, length):
        # 定义包含英文大写字母和数字的字符集
        characters = string.ascii_lowercase + string.digits
        # 从字符集中随机选择length个字符并拼接起来
        random_string = ''.join(random.choice(characters) for _ in range(length))
        return random_string

    def get_point(self):
        start_x, start_y, step = 800, 476, 5
        points = []
        pause = 0
        steps = random.randint(38, 64)
        for i in range(steps):
            x = start_x + i * step
            y = start_y + random.randint(-5, 5)
            pause += random.randint(30, 50)
            points.append([x, y, pause])
        return points

    def download_img(self, filename, bs):
        with open(filename, mode='wb') as fp:
            fp.write(bs)
            logger.info("{} 下载完成!".format(filename))

    def format_to_dict(self, data):
        return json.loads(data.strip('ypjsonp')[1:-1])

    def my_aes(self, data, key, iv):
        """
        AES加密
        :param data:
        :param key:
        :param iv:
        :return:
        """
        key = key.encode("utf-8")
        iv = iv.encode("utf-8")
        aes = AES.new(key=key, iv=iv, mode=AES.MODE_CBC)
        data = pad(data.encode("utf-8"), 16)
        return base64.b64encode(aes.encrypt(data)).decode("utf-8")

    def pass_slide(self):
        '''滑块全流程'''
        logger.info('云片滑块验证'.center(100, '='))
        # while True:
        img_width = 306
        alert_img_width = 59
        rsa_pub_key = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDnOWe/gs033L/2/xR3oi6SLAMPBY5VledUqqH6dbCNOdrGX4xW+1x6NUfvmwpHRBA2C7xWDDvOIldTl0rMtERTDy9homrVqEcW6/TY+dSVFL3e2Yg2sVaehHv7FhmATkgfC2FcXt8Wvm99QpKRSrGKpcFYJwOj2F8hJh+rTG0IPQIDAQAB'

        address = "https://gitee.com"
        encrypt_dict0 = {
            "browserInfo": [
                {
                    "key": "userAgent",
                    "value": self.session.headers['User-Agent']
                },
                {
                    "key": "language",
                    "value": "zh-CN"
                },
                {
                    "key": "hardware_concurrency",  # cpu核数
                    "value": 12
                },
                {
                    "key": "resolution",
                    "value": [
                        1920,
                        1080
                    ]
                },
                {
                    "key": "navigator_platform",
                    "value": "Win32"
                }
            ],
            "nativeInfo": None,
            "additions": {},
            "options": {
                "sdk": "https://gitee.com/static/javascripts/yunpian/riddler-sdk-0.2.2.js?t=1629687362163",
                "sdkBuildVersion": "1.5.0(2021080901)",
                "hosts": "https://captcha.yunpian.com"
            },
            "fp": self.fp,
            "address": address,
            "yp_riddler_id": self.yp_riddler_id
        }
        i = self.my_aes(
            data=dumps(encrypt_dict0),
            key=self.key,
            iv=self.iv,
        )
        k = my_rsa(rsa_pub_key, self.key + self.iv)

        response = self.session.get("https://captcha.yunpian.com/v1/jsonp/captcha/get", params={
            "cb": random_cb(),
            "i": i,
            "k": k,
            "captchaId": self.captchaId
        })
        js_data = self.format_to_dict(response.text)
        logger.info(f'GET: {js_data}')
        token = js_data["data"]["token"]

        target_bytes = requests.get(js_data["data"]["front"]).content
        background_bytes = requests.get(js_data["data"]["bg"]).content
        # self.download_img("bg.png", background_bytes)
        # self.download_img("front.png", target_bytes)

        distance = ocr_slide_distance(target_bytes, background_bytes)
        verify_url = "https://captcha.yunpian.com/v1/jsonp/captcha/verify"
        points = self.get_point()
        logger.info(f'distance: {distance} points: {points}')

        distanceX = ((img_width - alert_img_width) * ((distance) / (img_width - 42))) / img_width
        # logger.info(f'distance:{distance}  <=> distanceX: {distanceX}')
        encrypt_dict1 = {
            "points": points,
            "distanceX": distanceX,
            "fp": self.fp,
            "address": address,
            "yp_riddler_id": self.yp_riddler_id
        }
        i = self.my_aes(
            data=dumps(encrypt_dict1),
            key=self.key,
            iv=self.iv,
        )
        k = my_rsa(rsa_pub_key, self.key + self.iv)
        params = {
            "cb": random_cb(),
            "i": i,  # aes
            "k": k,  # rsa
            "token": token,
            "captchaId": self.captchaId
        }
        # 延时操作
        time.sleep(random.uniform(1, 2))
        response = self.session.get(verify_url, params=params)
        data_dict = self.format_to_dict(response.text)
        logger.info(f'VERIFY: {data_dict}')
        return data_dict


if __name__ == '__main__':
    obj = CloudSheet(captcha_id='5de60e59c04d4dab96bdbc312370ad26',fp='681eca63c60fc9505bd2e14332569c62',yp_riddler_id='55551ce6-7b80-4a17-8fdd-8ac689f442cc')
    obj.pass_slide()